/******************************************************************************
//             INTEL CORPORATION PROPRIETARY INFORMATION
//  This software is supplied under the terms of a license agreement or
//  nondisclosure agreement with Intel Corporation and may not be copied
//  or disclosed except in accordance with the terms of that agreement.
//    Copyright(c) 2000 - 2001 Intel Corporation. All Rights Reserved.
//
//  VSS: 
//     $Workfile: $
//     $Revision: $
//     $Date:     $
//     $Archive:  $
//
//  Description:
//      Intel(R) Integrated Performance Primitives - JPEG Helper file.
//      This file contains Huffman decoding (Progressive) functions.
//
//  History:
//     Date         Author        Changes
//     2001/1/20   Jerry Hu       Created (Version 0.2 Progressive)
//
********************************************************************************/

#include "_ippjpeg.h"
#include "ijdhufsh.h"


/******************************************************************************
// Name:             ippiDecodeHuffman_Direct_JPEG_DCFirst_1u16s
// Description:      Decodes DC value for the first scan.
// Input Arguments: 
//             pSrc: Identifies source huffman stream data.
//      pSrcBitsLen: Indicates the number of bits that have been decoded before.
//          pDCPred: Identifies the previous DC value of prediction.
//  pPrefetchedBits: Identifies prefetch buffer which contain the bits decoded 
//                   in the last time.
// pNumValidPrefetchedBits:
//                   Indicates number of valid bits in prefetch buffer.
//     pDCHuffTable: Identifies "IppJPEGDeHuffTable" data structure for DC decoding.
//              al:  Indiactes successive approximation bit position low (for point tranform)
//
// Output Arguments:
//      pSrcBitsLen: Indicates the number of bits that have been decoded after this function calling.
//             pDst: Identifies destination data in 8x8.
//          pDCPred: Identifies the current DC value of prediction.
//          pMarker: Identifies the marker decoded from stream.
//  pPrefetchedBits: Identifies prefetch buffer which contain the bits decoded 
//                   in current time.
// pNumValidPrefetchedBits:
//                   Indicates number of valid bits in prefetch buffer.
// Remarks:      
//                   1. The start address of "pDst" shall be aligned at 4byte boundary.
//                   2. It is better to do this alignment at 32byte boundary to optimize 
//                      D-Cache accessing.
//                   3. *pDCPred shall be 0 in initial or after each restart interval.
//                   4. *pMarker shall be 0 in initial or after it was processed.
//                   5: *pNumValidPrefetchedBits shall be 0 in following case
//                      1) Initial.
//                      2) After each restart interval.
//                      3) After each marker.
//
// Returns:         
//    IPP_STATUS_OK: Succeeds.
// IPP_STATUS_ERROR: Decoding error.
******************************************************************************/
IPPFUN(IppStatus, ippiDecodeHuffman_Direct_JPEG_DCFirst_1u16s)(const Ipp8u *pSrc,
                                                              int         *pSrcBitsLen,
                                                              Ipp16s      *pDst,
                                                              Ipp16s      *pDCPred,
                                                              int         *pMarker,
                                                              Ipp32u      *pPrefetchedBits,
                                                              int         *pNumValidPrefetchedBits,
                                                              int         al,
                                                              const IppJPEGDeHuffTable 
                                                                          *pDCHuffTable)
{
    int nLen;
    int value;
    int ssss;

    _stream stream;

    _IPP_CHECK_ARG(NULL!=pSrc);
    _IPP_CHECK_ARG((NULL!=pSrcBitsLen)&&(0<=*pSrcBitsLen));
    _IPP_CHECK_ARG(NULL!=pDst);
    _IPP_CHECK_ARG(_IPP_CHECK_ALIGN_4BYTE(pDst));
    _IPP_CHECK_ARG(NULL!=pDCPred);
    _IPP_CHECK_ARG(NULL!=pMarker);
    _IPP_CHECK_ARG(NULL!=pPrefetchedBits);
    _IPP_CHECK_ARG(NULL!=pNumValidPrefetchedBits);
    _IPP_CHECK_ARG(0<=*pNumValidPrefetchedBits);
    _IPP_CHECK_ARG(0<=al);
    _IPP_CHECK_ARG(NULL!=pDCHuffTable);

    nLen=(*pSrcBitsLen+7)>>3;
    stream.pHeadStreamBuffer=pSrc;
    stream.pStreamBuffer=&pSrc[nLen];
    stream.nUsedBytesLen=nLen;
    stream.pMarker=pMarker;
    stream.pnPrefetchedBits=pPrefetchedBits;
    stream.pnNumValidBits=pNumValidPrefetchedBits;

    /* Decode DC coef */
    ssss=_IppHuffDecode(pDCHuffTable,&stream);

    if (0>ssss) {
       return (IppStatus)((-256==ssss)?IPP_STATUS_OK:IPP_STATUS_ERROR);
    }

    if (ssss) {

        ssss&=0x0f; /* Make sure s is in [0,15] */
        _CHECKPREVIEWBITSNUM(ssss, &stream, IPP_STATUS_ERROR);
        _GETBITS(value, ssss, &stream);

        if (value<(1<<(ssss-1))) {
           value+=_nLowestCoef[ssss]; /* Negative Value */
        }

        *pDCPred = (Ipp16s)(*pDCPred+value);
    } /* if (ssss) */

    *pDst = (Ipp16s)(*pDCPred << al);

    *pSrcBitsLen=((stream.nUsedBytesLen)<<3);

    return IPP_STATUS_OK;
}

/******************************************************************************
// Name:             ippiDecodeHuffman_Direct_JPEG_DCRefine_1u16s
// Description:      Decodes DC value for the refine scan.
// Input Arguments: 
//             pSrc: Identifies source huffman stream data.
//      pSrcBitsLen: Indicates the number of bits that have been decoded before.
//  pPrefetchedBits: Identifies prefetch buffer which contain the bits decoded 
//                   in the last time.
// pNumValidPrefetchedBits:
//                   Indicates number of valid bits in prefetch buffer.
//              al:  Indiactes successive approximation bit position low (for point tranform)
//
// Output Arguments:
//             pDst: Identifies destination data in 8x8.
//          pMarker: Identifies the marker decoded from stream.
//  pPrefetchedBits: Identifies prefetch buffer which contain the bits decoded 
//                   in current time.
// pNumValidPrefetchedBits:
//                   Indicates number of valid bits in prefetch buffer.
// Remarks:      
//                   1. The start address of "pDst" shall be aligned at 4byte boundary.
//                   2. It is better to do this alignment at 32byte boundary to optimize 
//                      D-Cache accessing.
//                   3. *pMarker shall be 0 in initial or after it was processed.
//                   4: *pNumValidPrefetchedBits shall be 0 in following case
//                      1) Initial.
//                      2) After each restart interval.
//                      3) After each marker.
//
// Returns:         
//    IPP_STATUS_OK: Succeeds.
// IPP_STATUS_ERROR: Decoding error.
******************************************************************************/
IPPFUN(IppStatus, ippiDecodeHuffman_Direct_JPEG_DCRefine_1u16s)(const Ipp8u *pSrc,
                                                               int         *pSrcBitsLen,
                                                               Ipp16s      *pDst,
                                                               int         *pMarker,
                                                               Ipp32u      *pPrefetchedBits,
                                                               int         *pNumValidPrefetchedBits,
                                                               int         al)
{
    int nLen;
    int bit;

    _stream stream;

    _IPP_CHECK_ARG(NULL!=pSrc);
    _IPP_CHECK_ARG((NULL!=pSrcBitsLen)&&(0<=*pSrcBitsLen));
    _IPP_CHECK_ARG(NULL!=pDst);
    _IPP_CHECK_ARG(_IPP_CHECK_ALIGN_4BYTE(pDst));
    _IPP_CHECK_ARG(NULL!=pMarker);
    _IPP_CHECK_ARG(NULL!=pPrefetchedBits);
    _IPP_CHECK_ARG(NULL!=pNumValidPrefetchedBits);
    _IPP_CHECK_ARG(0<=*pNumValidPrefetchedBits);
    _IPP_CHECK_ARG(0<=al);

    nLen=(*pSrcBitsLen+7)>>3;
    stream.pHeadStreamBuffer=pSrc;
    stream.pStreamBuffer=&pSrc[nLen];
    stream.nUsedBytesLen=nLen;
    stream.pMarker=pMarker;
    stream.pnPrefetchedBits=pPrefetchedBits;
    stream.pnNumValidBits=pNumValidPrefetchedBits;

    /* Decode DC coef */
    bit = 0;

    _CHECKPREVIEWBITSNUM(1, &stream, IPP_STATUS_ERROR);
    _GETBITS(bit, 1, &stream);

    if (bit) {
        *pDst |= (1<<al);
    }

    *pSrcBitsLen=((stream.nUsedBytesLen)<<3);

    return IPP_STATUS_OK;
}

/******************************************************************************
// Name:             ippiDecodeHuffman_Direct_JPEG_ACFirst_1u16s
// Description:      Decodes AC values for the first scan.
// Input Arguments: 
//             pSrc: Identifies source huffman stream data.
//      pSrcBitsLen: Indicates the number of bits that have been decoded before.
//          pEOBRun: Identifies EOB run length in last time.
//  pPrefetchedBits: Identifies prefetch buffer which contain the bits decoded 
//                   in the last time.
// pNumValidPrefetchedBits:
//                   Indicates number of valid bits in prefetch buffer.
//               ss: Indicates start of selection.
//               se: Indicates end of selection.
//               al: Indiactes successive approximation bit position low (for point tranform)
//
//     pACHuffTable: Identifies "IppJPEGDeHuffTable" data structure for AC decoding.
//
// Output Arguments:
//             pDst: Identifies destination data in 8x8.
//          pEOBRun: Identifies EOB run length in current time.
//          pMarker: Identifies the marker decoded from stream.
//  pPrefetchedBits: Identifies prefetch buffer which contain the bits decoded 
//                   in current time.
// pNumValidPrefetchedBits:
//                   Indicates number of valid bits in prefetch buffer.
//
// Remarks:      
//                   1. The start address of "pDst" shall be aligned at 4byte boundary.
//                   2. It is better to do this alignment at 32byte boundary to optimize 
//                      D-Cache accessing.
//                   3. *pDCPred shall be 0 in initial or after each restart interval.
//                   4. *pMarker shall be 0 in initial or after it was processed.
//                   5: *pNumValidPrefetchedBits shall be 0 in following case
//                      1) Initial.
//                      2) After each restart interval.
//                      3) After each marker.
//
// Returns:         
//    IPP_STATUS_OK: Succeeds.
// IPP_STATUS_ERROR: Decoding error.
******************************************************************************/
IPPFUN(IppStatus, ippiDecodeHuffman_Direct_JPEG_ACFirst_1u16s)(const Ipp8u *pSrc,
                                                              int         *pSrcBitsLen,
                                                              Ipp16s      *pDst,
                                                              int         *pEOBRun,
                                                              int         *pMarker,
                                                              Ipp32u      *pPrefetchedBits,
                                                              int         *pNumValidPrefetchedBits,
                                                              int         ss,
                                                              int         se,
                                                              int         al,
                                                              const IppJPEGDeHuffTable 
                                                                          *pACHuffTable)
{
    int k;  
    int nLen;
    int value;
    int rrrr, ssss, rs;

    _stream stream;

    _IPP_CHECK_ARG(NULL!=pSrc);
    _IPP_CHECK_ARG((NULL!=pSrcBitsLen)&&(0<=*pSrcBitsLen));
    _IPP_CHECK_ARG(NULL!=pDst);
    _IPP_CHECK_ARG(_IPP_CHECK_ALIGN_4BYTE(pDst));
    _IPP_CHECK_ARG((NULL!=pEOBRun)&&(0<=*pEOBRun));
    _IPP_CHECK_ARG(NULL!=pMarker);
    _IPP_CHECK_ARG(NULL!=pPrefetchedBits);
    _IPP_CHECK_ARG(NULL!=pNumValidPrefetchedBits);
    _IPP_CHECK_ARG(0<=*pNumValidPrefetchedBits);
    _IPP_CHECK_ARG((0<=al)&&(0<ss)&&(ss<=se)&&(64>se));
    _IPP_CHECK_ARG(NULL!=pACHuffTable);

    if (0<(*pEOBRun)) {
        (*pEOBRun)--;
        return IPP_STATUS_OK;
    }

    nLen=(*pSrcBitsLen+7)>>3;
    stream.pHeadStreamBuffer=pSrc;
    stream.pStreamBuffer=&pSrc[nLen];
    stream.nUsedBytesLen=nLen;
    stream.pMarker=pMarker;
    stream.pnPrefetchedBits=pPrefetchedBits;
    stream.pnNumValidBits=pNumValidPrefetchedBits;

    /* Decode AC coefficient */
    for (k=ss; k<=se; k++) {
        rs=_IppHuffDecode(pACHuffTable, &stream);
        if (0>rs) {
            if (-256==rs) {
                *pNumValidPrefetchedBits=0;
                *pSrcBitsLen=((stream.nUsedBytesLen)<<3);
                return IPP_STATUS_OK;
            }
            return IPP_STATUS_ERROR;
        }
        rrrr  = (rs>>4);
        ssss  = rs&0x0f;

        if (ssss) {
           k+=rrrr;
           _CHECKPREVIEWBITSNUM(ssss, &stream, IPP_STATUS_ERROR);
           _GETBITS(value, ssss, &stream);
           if ( (value & (1<<(ssss-1)))==0 ) {
               value+=_nLowestCoef[ssss];
           }
           pDst[_nIppIZigZagIndex[k]] = (Ipp16s)(value<<al);

        } else {
            if (15==rrrr) {
                k+=15;
            } else {
                (*pEOBRun)=1<<rrrr;
                if (rrrr) {
                   _CHECKPREVIEWBITSNUM(rrrr, &stream, IPP_STATUS_ERROR);
                   _GETBITS(value, rrrr, &stream);
                   (*pEOBRun)+=value;
                }
                (*pEOBRun)--;
                break;
            }
        }
    }

    /* Adjust the current point in the stream buffer */
    *pSrcBitsLen=((stream.nUsedBytesLen)<<3);

    return IPP_STATUS_OK;
}

/******************************************************************************
// Name:             ippiDecodeHuffman_Direct_JPEG_ACRefine_1u16s
// Description:      Decodes AC values for the first scan.
// Input Arguments: 
//             pSrc: Identifies source huffman stream data.
//      pSrcBitsLen: Indicates the number of bits that have been decoded before.
//          pEOBRun: Identifies EOB run length in last time.
//  pPrefetchedBits: Identifies prefetch buffer which contain the bits decoded 
//                   in the last time.
// pNumValidPrefetchedBits:
//                   Indicates number of valid bits in prefetch buffer.
//               ss: Indicates start of selection.
//               se: Indicates end of selection.
//               al: Indiactes successive approximation bit position low (for point tranform)
//
//     pACHuffTable: Identifies "IppJPEGDeHuffTable" data structure for AC decoding.
//
// Output Arguments:
//             pDst: Identifies destination data in 8x8.
//          pEOBRun: Identifies EOB run length in current time.
//          pMarker: Identifies the marker decoded from stream.
//  pPrefetchedBits: Identifies prefetch buffer which contain the bits decoded 
//                   in current time.
// pNumValidPrefetchedBits:
//                   Indicates number of valid bits in prefetch buffer.
//
// Remarks:      
//                   1. The start address of "pDst" shall be aligned at 4byte boundary.
//                   2. It is better to do this alignment at 32byte boundary to optimize 
//                      D-Cache accessing.
//                   3. *pDCPred shall be 0 in initial or after each restart interval.
//                   4. *pMarker shall be 0 in initial or after it was processed.
//                   5: *pNumValidPrefetchedBits shall be 0 in following case
//                      1) Initial.
//                      2) After each restart interval.
//                      3) After each marker.
//
// Returns:         
//    IPP_STATUS_OK: Succeeds.
// IPP_STATUS_ERROR: Decoding error.
******************************************************************************/
IPPFUN(IppStatus, ippiDecodeHuffman_Direct_JPEG_ACRefine_1u16s)(const Ipp8u *pSrc,
                                                         int         *pSrcBitsLen,
                                                         Ipp16s      *pDst,
                                                         int         *pEOBRun,
                                                         int         *pMarker,
                                                         Ipp32u      *pPrefetchedBits,
                                                         int         *pNumValidPrefetchedBits,
                                                         int         ss,
                                                         int         se,
                                                         int         al,
                                                         const IppJPEGDeHuffTable 
                                                                     *pACHuffTable)
{
    int k;  
    int nLen;
    int temp;
    int nNegVal, nPosVal;
    int rrrr, ssss, rs;
    Ipp16s *pZZPtr;

    _stream stream;

    _IPP_CHECK_ARG(NULL!=pSrc);
    _IPP_CHECK_ARG((NULL!=pSrcBitsLen)&&(0<=*pSrcBitsLen));
    _IPP_CHECK_ARG(NULL!=pDst);
    _IPP_CHECK_ARG(_IPP_CHECK_ALIGN_4BYTE(pDst));
    _IPP_CHECK_ARG((NULL!=pEOBRun)&&(0<=*pEOBRun));
    _IPP_CHECK_ARG(NULL!=pMarker);
    _IPP_CHECK_ARG(NULL!=pPrefetchedBits);
    _IPP_CHECK_ARG(NULL!=pNumValidPrefetchedBits);
    _IPP_CHECK_ARG(0<=*pNumValidPrefetchedBits);
    _IPP_CHECK_ARG((0<=al)&&(0<ss)&&(ss<=se)&&(64>se));
    _IPP_CHECK_ARG(NULL!=pACHuffTable);

    k=ss;
    nPosVal=(1)<<al;
    nNegVal=(-1)<<al; 
    nLen=(*pSrcBitsLen+7)>>3;
    stream.pHeadStreamBuffer=pSrc;
    stream.pStreamBuffer=&pSrc[nLen];
    stream.nUsedBytesLen=nLen;
    stream.pMarker=pMarker;
    stream.pnPrefetchedBits=pPrefetchedBits;
    stream.pnNumValidBits=pNumValidPrefetchedBits;
    
    if (0==(*pEOBRun)) {
        for (; k<=se; k++) {
            rs=_IppHuffDecode(pACHuffTable, &stream);
            if (0>rs) {
                if (-256==rs) {
                    *pNumValidPrefetchedBits=0;
                    *pSrcBitsLen=((stream.nUsedBytesLen)<<3);
                    return IPP_STATUS_OK;
                }
                return IPP_STATUS_ERROR;
            }
            rrrr = rs>>4;
            ssss = rs&0x0f;
            if (ssss) {
                /* meet zero-history data */
                _CHECKPREVIEWBITSNUM(1, &stream, IPP_STATUS_ERROR);
                _GETBITS(temp, 1, &stream);
                ssss=temp?nPosVal:nNegVal;
            } else { /* if (!ssss) */
                /* meet EOB, EOBn or ZRL */
                if (rrrr!=15) { 
                    /* meet EOBn or EOB */
                    (*pEOBRun)=1<<rrrr;
                    if (rrrr){
                        _CHECKPREVIEWBITSNUM(rrrr, &stream, IPP_STATUS_ERROR);
                        _GETBITS(temp, rrrr, &stream);
                        (*pEOBRun)+=temp;
                    }
                    break;    
                }/* if (rrrr!=15) */
                /* meet ZRL */
            } /* else */

            do {
                pZZPtr=&pDst[_nIppIZigZagIndex[k]];
                if (0!=pZZPtr[0]) {
                    /* meet non-zero-history item */
                    _CHECKPREVIEWBITSNUM(1, &stream, IPP_STATUS_ERROR);
                    _GETBITS(temp, 1, &stream);
                    /* do nothing if appended bit is 0 */
                    if (0!=temp) {
                        /* do nothing if already set it */
                        if (0==(pZZPtr[0]&nPosVal)) {
                            if (0<=pZZPtr[0]) {
                                pZZPtr[0]=(Ipp16s)(pZZPtr[0]+nPosVal);
                            } else {
                                pZZPtr[0]=(Ipp16s)(pZZPtr[0]+nNegVal);
                            }
                        }
                    } /* if (0!=temp) */
                } else {/* if (0==pZZPtr[0]) */
                    /* process ZRL */
                    if (0>--rrrr) {
                        break;
                    }
                }
                k++;
            } while (k<=se);

            if (ssss) {
                /* set zero-history item */
                pDst[_nIppIZigZagIndex[k]]=(Ipp16s)ssss; 
            }
            
        } /* for (; k<se; k++) */
    } /* if (0==(*pEOBRun)) */

    if (0<(*pEOBRun)) {
        /* append bits */
        for (; k<=se; k++) {
            pZZPtr=&pDst[_nIppIZigZagIndex[k]];
            if (0==pZZPtr[0]) {
                continue;
            }
            /* meet non-zero-history item */
            _CHECKPREVIEWBITSNUM(1, &stream, IPP_STATUS_ERROR);
            _GETBITS(temp, 1, &stream);
            /* do nothing if appended bit is 0 */
            if (0!=temp) {
                /* do nothing if already set it */
                if (0==(pZZPtr[0]&nPosVal)) {
                    if (0<=pZZPtr[0]) {
                        pZZPtr[0]=(Ipp16s)(pZZPtr[0]+nPosVal);
                    } else {
                        pZZPtr[0]=(Ipp16s)(pZZPtr[0]+nNegVal);
                    }
                }
            } /* if (0!=temp) */
        }
        (*pEOBRun)--;
    }/* if (0<(*pEOBRun)) */

    /* Adjust the current point in the stream buffer */
    *pSrcBitsLen=((stream.nUsedBytesLen)<<3);

    return IPP_STATUS_OK;
}

/* EOF */
